using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Collections.Generic;

namespace Elte.SqlSpIdx
{
    public partial class MatrixOperations
    {

        [Microsoft.SqlServer.Server.SqlFunction]
        public static SqlBinary MatrixTranspose(SqlBinary m)
        {
            Mapack.Matrix mm = new Mapack.Matrix(Converters.MatrixConverter.ToArray(m.Value));
            return new SqlBinary(Converters.MatrixConverter.ToBinary(mm.Transpose().Array));
        }

        [Microsoft.SqlServer.Server.SqlFunction]
        public static SqlBinary MatrixInverse(SqlBinary m)
        {
            Mapack.Matrix mm = new Mapack.Matrix(Converters.MatrixConverter.ToArray(m.Value));
            return new SqlBinary(Converters.MatrixConverter.ToBinary(mm.Inverse.Array));
        }

        [Microsoft.SqlServer.Server.SqlFunction]
        public static SqlDouble MatrixDeterminant(SqlBinary m)
        {
            Mapack.Matrix mm = new Mapack.Matrix(Converters.MatrixConverter.ToArray(m.Value));
            return new SqlDouble(mm.Determinant);
        }

        [Microsoft.SqlServer.Server.SqlFunction]
        public static SqlDouble MatrixNorm(SqlBinary m)
        {
            Mapack.Matrix mm = new Mapack.Matrix(Converters.MatrixConverter.ToArray(m.Value));
            return new SqlDouble(mm.Norm1);
        }

        [Microsoft.SqlServer.Server.SqlFunction]
        public static SqlDouble MatrixTrace(SqlBinary m)
        {
            Mapack.Matrix mm = new Mapack.Matrix(Converters.MatrixConverter.ToArray(m.Value));
            return new SqlDouble(mm.Trace);
        }

        [Microsoft.SqlServer.Server.SqlFunction]
        public static SqlBinary MatrixProd(SqlBinary m1, SqlBinary m2)
        {
            Mapack.Matrix mm1 = new Mapack.Matrix(Converters.MatrixConverter.ToArray(m1.Value));
            Mapack.Matrix mm2 = new Mapack.Matrix(Converters.MatrixConverter.ToArray(m2.Value));
            
            return new SqlBinary(Converters.MatrixConverter.ToBinary((mm1 * mm2).Array));
        }

        public static double[] VectorProd(double[][] m, double[] v)
        {
            double[] res = new double[v.Length];

            for (int i = 0; i < m.Length; i++)
            {
                res[i] = 0.0f;
                for (int j = 0; j < m[i].Length; j++)
                    res[i] += m[i][j] * v[j];
            }

            return res;
        }

        [Microsoft.SqlServer.Server.SqlFunction]
        public static SqlBinary MatrixVectorProd(SqlBinary matrix, SqlBinary vector)
        {
            // not using Mapack to spare transpose of vector

            double[][] m = Elte.SqlSpIdx.Converters.MatrixConverter.ToArray(matrix.Value);
            double[] v = Elte.SqlSpIdx.Converters.VectorConverter.ToArray(vector.Value);

            double[] res = VectorProd(m, v);

            return new SqlBinary(Converters.VectorConverter.ToBinary(res));
        }



    }
}